/// General mathematics routines

#ifndef MATH
#define MATH

#include "stuff.h"
#include <math.h>
#include <assert.h>

namespace Math
{
	const GLfloat epsilon = 0.00001f;                         ///< floating point epsilon for single precision. todo: verify epsilon value and usage
	const GLfloat epsilonSquared = epsilon * epsilon;         ///< epsilon value squared

	const GLfloat pi = 3.1415926f;                            ///< pi stored at a reasonable precision for single precision GLfloating point.

	/// test for floating point equality within [-epsilon, +epsilon]

	inline bool equal(GLfloat a, GLfloat b)
	{
		const GLfloat d = a - b;

		if (d < epsilon && d >- epsilon) 
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	/// determine the minimum floating point value

	inline GLfloat minimum(GLfloat a, GLfloat b)
	{
		if (a < b) 
		{
			return a;
		}
		else
		{
			return b;
		}
	}

	/// determine the maximum floating point value

	inline GLfloat maximum(GLfloat a, GLfloat b)
	{
		if(a > b)
		{
			return a;
		}
		else
		{
			return b;
		}
	}

	/// calculate the square root of a floating point number.

	inline GLfloat sqrt(GLfloat value)
	{
		assert(value >= 0);
		return (GLfloat)pow(value, 0.5f);
	}

	/// calculate the sine of a floating point angle in radians.

	inline GLfloat sin(GLfloat radians)
	{
		return (GLfloat) ::sin(radians);
	}

	/// calculate the cosine of a floating point angle in radians.

	inline GLfloat cos(GLfloat radians)
	{
		return (GLfloat) ::cos(radians);
	}

	/// calculate the tangent of a floating point angle in radians.

	inline GLfloat tan(GLfloat radians)
	{
		return (GLfloat) ::tan(radians);
	}

	/// calculate the arcsine of a floating point value. result is in radians.

	inline GLfloat asin(GLfloat value)
	{
		return (GLfloat) ::asin(value);
	}

	/// calculate the arccosine of a floating point value. result is in radians.

	inline GLfloat acos(GLfloat value)
	{
		return (GLfloat) ::acos(value);
	}

	/// calculate the arctangent of a floating point value y/x. result is in radians.

	inline GLfloat atan2(GLfloat y, GLfloat x)
	{
		return (GLfloat) ::atan2(y,x);
	}

	/// calculate the floor of a floating point value.
	/// the floor is the nearest integer strictly less than or equal to the GLfloating point number.

	inline GLfloat floor(GLfloat value)
	{
		return (GLfloat) ::floor(value);
	}

	/// calculate the ceiling of a floating point value.
	/// the ceil is the nearest integer strictly greater than or equal to the GLfloating point number.

	inline GLfloat ceiling(GLfloat value)
	{                     
		return (GLfloat) ::ceil(value);
	}

	/// quickly determine the sign of a floating point number.

	inline unsigned int sign(const GLfloat& v)
	{	
		return (((unsigned int&)v) & 0x80000000);
	}

	/// fast GLfloating point absolute value.

	inline GLfloat abs(GLfloat v)
	{
		*(int *)&v &= 0x7fffffff;
		return v;
	}

	/// interpolate between interval [a,b] with t in [0,1].

	inline GLfloat lerp(GLfloat a, GLfloat b, GLfloat t)
	{
		return a + (b - a) * t;
	}

	/// snap GLfloating point number to grid.

	inline GLfloat snap(GLfloat p, GLfloat grid)
	{
		return grid ? GLfloat(floor((p + grid * 0.5f) / grid) * grid) : p;
	}
}

#endif